package org.bjf.modules.sys.service;

import static org.bjf.modules.sys.listenner.LiveBeanPostProcessor.PERMISSION_MAP;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bjf.cache.CacheNameConfig.RedisCacheEnum.Names;
import org.bjf.modules.core.service.BaseService;
import org.bjf.modules.sys.bean.ControllerResource;
import org.bjf.modules.sys.bean.SysAcl;
import org.bjf.modules.sys.bean.SysMenu;
import org.bjf.modules.sys.bean.SysRole;
import org.bjf.modules.sys.bean.SysUserRole;
import org.bjf.modules.sys.enums.AclEnum.PrincipalType;
import org.bjf.modules.sys.enums.AclEnum.ResourceType;
import org.bjf.modules.sys.mapper.SysRoleMapper;
import org.bjf.modules.sys.query.SysAclQuery;
import org.bjf.modules.sys.query.SysRoleQuery;
import org.bjf.modules.sys.query.SysUserRoleQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
 * @author bjf
 * @date 2017/11/27
 */
@Service
@Slf4j
public class SysRoleService extends BaseService<SysRoleMapper, SysRole, SysRoleQuery> {

  @Autowired
  private SysUserRoleService userRoleService;
  @Autowired
  private SysAclService aclService;
  @Autowired
  private SysMenuService menuService;
  @Autowired
  private SysUserService sysUserService;

  @Override
  protected EntityWrapper<SysRole> buildQuery(SysRoleQuery q) {
    if (q == null) {
      return null;
    }
    EntityWrapper<SysRole> ew = new EntityWrapper<>();
    ew.eq(q.getPid() != null, "pid", q.getPid());
    ew.eq(StringUtils.isNotBlank(q.getRoleName()), "role_name", q.getRoleName());
    ew.in(!CollectionUtils.isEmpty(q.getRoleIdList()), "sys_role_id", q.getRoleIdList());
    return ew;
  }

  /**
   * 查询用户角色
   */
  @Cacheable(value = Names.SYS, key = "'live:role:listByUser:' + #sysUserId")
  public List<SysRole> listByUser(long sysUserId) {
    SysUserRoleQuery query = new SysUserRoleQuery();
    query.setSysUserId(sysUserId);
    List<SysUserRole> userRoles = userRoleService.listAll(query);
    if (userRoles.isEmpty()) {
      return Collections.EMPTY_LIST;
    }

    SysRoleQuery q = new SysRoleQuery();
    q.setRoleIdList(userRoles.stream().map(SysUserRole::getSysRoleId).collect(Collectors.toList()));

    return this.listAll(q);
  }

  /**
   * 全量更新角色的controller权限
   */
  @Transactional(rollbackFor = Exception.class)
  public void updateControllerPermission(long roleId,
      List<ControllerResource> resources) {
    //===1.先删除角色全部权限
    EntityWrapper<SysAcl> ew = new EntityWrapper<>();
    ew.eq("principal_type", PrincipalType.ROLE.getType());
    ew.eq("principal_id", roleId);
    ew.eq("resource_type", ResourceType.CONTROLLER.getType());
    aclService.delete(ew);

    //===2.新增用户权限
    for (ControllerResource resource : resources) {
      if (!PERMISSION_MAP.containsKey(resource.getResSn())) {
        continue;
      }
      SysAcl acl = new SysAcl();
      acl.setPrincipalType(PrincipalType.ROLE.getType());
      acl.setPrincipalId(roleId);
      acl.setResourceType(ResourceType.CONTROLLER.getType());
      String resourceId = PERMISSION_MAP.get(resource.getResSn()).getResSn();
      acl.setResourceId(resourceId);
      acl.setAclState(Integer.parseInt(resource.getAcl(), 2));
      aclService.add(acl);
    }
    sysUserService.clearUserCache();

  }

  /**
   * 给角色分配菜单
   */
  @Transactional(rollbackFor = Exception.class)
  @CacheEvict(value = Names.SYS, key = "'live:role:listMenu:' + #roleId")
  public void updateMenu(Long roleId, String menuIds) {
    //===1.先删除角色的菜单
    EntityWrapper<SysAcl> ew = new EntityWrapper<>();
    ew.eq("principal_type", PrincipalType.ROLE.getType());
    ew.eq("principal_id", roleId);
    ew.eq("resource_type", ResourceType.MENU.getType());
    aclService.delete(ew);

    //===2.新增角色菜单
    String[] arr = StringUtils.split(menuIds, ",");
    List<SysAcl> list = new ArrayList<>();
    for (String menuId : arr) {
      SysAcl acl = new SysAcl();
      acl.setPrincipalType(PrincipalType.ROLE.getType());
      acl.setPrincipalId(roleId);
      acl.setResourceType(ResourceType.MENU.getType());
      acl.setResourceId(String.valueOf(menuId));

      list.add(acl);
    }

    if (!list.isEmpty()) {
      aclService.insertBatch(list);
    }

    //===3.清除用户菜单缓存
    sysUserService.clearUserCache();
  }

  /**
   * 查询角色菜单
   */
  public List<SysMenu> listMenu(List<Long> roleIdList) {
    List<SysMenu> all = new ArrayList<>();
    for (Long roleId : roleIdList) {
      all.addAll(listMenu(roleId));
    }
    return all;

  }

  /**
   * 查询角色菜单
   */
  @Cacheable(value = Names.SYS, key = "'live:role:listMenu:' + #roleId")
  public List<SysMenu> listMenu(Long roleId) {
    //===1.根据角色查acl菜单
    SysAclQuery aclQuery = new SysAclQuery();
    aclQuery.setPrincipalType(PrincipalType.ROLE.getType());
    aclQuery.setPrincipalId(roleId);
    aclQuery.setResourceType(ResourceType.MENU.getType());
    List<SysAcl> aclList = aclService.listAll(aclQuery);

    //===2.查询菜单
    return menuService
        .listByIds(aclList.stream().map(SysAcl::getResourceId).collect(Collectors.toList()));
  }
}
